<?php


namespace app\controller;


use app\component\ExcelComponent;
use app\model\Book;
use app\model\BookCategory;
use app\model\BookCategoryMap;
use app\model\BookFitReader;
use app\model\BookListDetail;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ExcelException;
use Predis\Client;
use svrlog\LogComponent;
use Taskinfo\taskReq;

class BookListController
{
    const DATAFILE_PATH = './runtime/datafile/';
    const BOOKDATA_PREFIX = 'bookdata_';
    const COMPANYERR_PREFIX = 'companyErr_';
    const ISBNERR_PREFIX = 'isbnErr_';
    const WRITEBOOKERR_PREFIX = 'writebookErr_';
    const FITREADERERR_PROFIX = 'fitreaderErr_';
    const CATEGORYERR_PROFIX = 'categoryErr_';
    const BOOKLISTDETAILERR_PROFIX = 'booklistdetailErr_';

    private $taskId = 0;
    private $listId = 0;
    private $path = '';
    private $columnConf = [];

    /**
     * @param $serv \Swoole\Server
     * @param $fd int
     * @param $data string
     */
    public function start($serv, $fd, $data)
    {
        $taskreq = new taskReq();
        $taskreq->mergeFromString($data);
        $this->taskId = $taskreq->getInt64TaskId();
        $this->listId = $taskreq->getInt64ListId();
        $this->path = $taskreq->getBytesPath();
        $this->columnConf = json_decode($taskreq->getBytesColumnConf(), true);

        $res = $this->readExcel();
        if ($res != 0) {
            LogComponent::writeLog()->error('readexcel error: ' . $this->taskId);
            return -1;
        }
        $this->checkCompany();
        $this->checkISBN();
        $this->writeBook();
        $serv->send($fd, "ok");
    }

    private function readExcel()
    {
        $excel = new ExcelComponent();
        try {
            $book = $excel->reader($this->path);
            //删除表头
            unset($book[0]);
            //重新排序数组，下标从0开始
            $book = array_merge($book);
            $datafile = self::BOOKDATA_PREFIX . $this->taskId . '.json';
            file_put_contents(self::DATAFILE_PATH . $datafile, json_encode($book));
            return 0;
        } catch (ExcelException $e) {
            LogComponent::writeLog()->error('read excel err: ' . $e->getMessage());
            return -1;
        } catch (\Exception $e) {
            LogComponent::writeLog()->error('unknown err: ' . $e->getMessage());
            return -2;
        }
    }

    /**
     * 清洗数据-校验出版社
     * @param $taskId
     * @return int
     */
    private function checkCompany()
    {
        $companyErr = [];
        $book = file_get_contents(self::DATAFILE_PATH . self::BOOKDATA_PREFIX . $this->taskId . '.json');
        $book = json_decode($book, true);
        $company = array_column($book, $this->columnConf['PressPos'] - 1);

        $redis = new Client();
        foreach ($company as $k => $v) {
            $v = str_replace(" ",'',$v);
            $val = $redis->get($v);
            //为空说明出版社不在db中
            if (empty($val)) {
                //记录出错的数据行
                $companyErr[$k] = $book[$k];
                //从源数据里删除错误的图书数据
                unset($book[$k]);
            }
        }

        unset($company);

        if (count($companyErr) > 0) {
            //记录错误数据
            file_put_contents(self::DATAFILE_PATH . self::COMPANYERR_PREFIX . $this->taskId . '.json', json_encode($companyErr));
            //更新源数据
            $book = array_merge($book);
            file_put_contents(self::DATAFILE_PATH . self::BOOKDATA_PREFIX . $this->taskId . '.json', json_encode($book));
        }
        LogComponent::writeLog()->info('checkCompany list:'.$this->taskId.', error: '.count($companyErr).' total: ' . count($book));

        return 0;
    }

    /**
     * 清洗数据-校验图书ISBN
     * @param $taskId
     * @return int
     */
    private function checkISBN()
    {
        $isbnErr = [];
        $book = file_get_contents(self::DATAFILE_PATH . self::BOOKDATA_PREFIX . $this->taskId . '.json');
        $book = json_decode($book, true);
        $isbn = array_column($book, $this->columnConf['IsbnPos'] - 1);

        $redis = new Client();
        foreach ($isbn as $k => $v) {
            $val = $redis->get($v);
            //不为空说明数据重复
            if (!empty($val)) {
                //记录出错的数据行
                $isbnErr[$k] = $book[$k];
                //从源数据里删除错误的图书数据
                unset($book[$k]);
            }
        }

        if (count($isbnErr) > 0) {
            //记录错误数据
            file_put_contents(self::DATAFILE_PATH . self::ISBNERR_PREFIX . $this->taskId . '.json', json_encode($isbnErr));
            //更新源数据
            $book = array_merge($book);
            file_put_contents(self::DATAFILE_PATH . self::BOOKDATA_PREFIX . $this->taskId . '.json', json_encode($book));
        }
        LogComponent::writeLog()->info('checkISBN list:'.$this->taskId.', error: '.count($isbnErr).' total: ' . count($book));

        return 0;
    }

    /**
     * 写入图书数据
     * @param $taskId
     * @return int
     */
    private function writeBook()
    {
        $writeErr = [];
        $book = file_get_contents(self::DATAFILE_PATH . self::BOOKDATA_PREFIX . $this->taskId . '.json');
        $book = json_decode($book, true);
        $redis = new Client();
        foreach ($book as $key => $item) {
            $data = [];
            $data['ISBN'] = $item[$this->columnConf['IsbnPos'] - 1];
            $data['BarCode'] = $item[$this->columnConf['IsbnPos'] - 1];
            $data['Name'] = $item[$this->columnConf['BookNamePos'] - 1];
            $data['Author'] = $item[$this->columnConf['AuthorPos'] - 1];
            $data['CompanyID'] = $redis->get(str_replace(" ",'', $item[$this->columnConf['PressPos'] - 1]));
            $data['Price'] = $item[$this->columnConf['PricePos'] - 1];
            $data['PressDate'] = date('Y-m-d H:i:s', strtotime($item[$this->columnConf['PressDatePos'] - 1]));
            $data['BigImg'] = 0;
            $data['SmallImg'] = 0;
            $res = Book::on('default')->create($data);
            if (empty($res)) {
                $writeErr[] = $item;
                //从源数据删除错误数据
                unset($book[$key]);
                LogComponent::writeLog()->error('write book data err, list: ' . $this->taskId . ', ISBN: ' . $item[5]);
            } else {
                //存Redis
                $redis->set($item[5], $res->ID);
            }
        }

        if (count($writeErr) > 0) {
            //记录错误数据
            file_put_contents(self::DATAFILE_PATH . self::WRITEBOOKERR_PREFIX . $this->taskId . '.json', json_encode($writeErr));
            //更新源数据
            $book = array_merge($book);
            file_put_contents(self::DATAFILE_PATH . self::BOOKDATA_PREFIX . $this->taskId . '.json', json_encode($book));
        }

        LogComponent::writeLog()->info('writeBook list: ' . $this->taskId . ', error: '.count($writeErr).' total: ' . count($book));
        return 0;
    }

    /**
     * 写入适读对象
     * @param $taskId
     * @return int
     */
    public function writeBookFitReader($taskId)
    {
        $fitReaderErr = [];
        $book = file_get_contents(self::DATAFILE_PATH . self::BOOKDATA_PREFIX . $taskId . '.json');
        $book = json_decode($book, true);
        $redis = new Client();
        foreach ($book as $key => $item) {
            $firstRead = str_replace(" ",'', $item[8]);
            $bookId = $redis->get($item[5]);
            if (empty($bookId)) {
                $item['errmsg'] = 'empty';
                $fitReaderErr[] = $item;
                continue;
            }
            if (!empty($firstRead)) {
                $data = [];
                $level = $redis->get($firstRead);
                $data['BookId'] = $bookId;
                $data['FitReaderId'] = $level;
                $data['Level'] = 1;
                $res = BookFitReader::on('default')->create($data);
                if (empty($res)) {
                    $item['errlevel'] = 1;
                    $fitReaderErr[] = $item;
                }
            }

            $secondRead = str_replace(" ",'', $item[9]);
            if (!empty($secondRead)) {
                $level = $redis->get($secondRead);
                $data = [];
                $data['BookId'] = $bookId;
                $data['FitReaderId'] = $level;
                $data['Level'] = 2;
                $res = BookFitReader::on('default')->create($data);
                if (empty($res)) {
                    $item['errlevel'] = 2;
                    $fitReaderErr[] = $item;
                }
            }

            $thirdRead = str_replace(" ",'', $item[10]);
            if (!empty($thirdRead)) {
                $level = $redis->get($thirdRead);
                $data = [];
                $data['BookId'] = $bookId;
                $data['FitReaderId'] = $level;
                $data['Level'] = 3;
                $res = BookFitReader::on('default')->create($data);
                if (empty($res)) {
                    $item['errlevel'] = 3;
                    $fitReaderErr[] = $item;
                }
            }

            //是否适合教师阅读用第四适读者代替
            if ($item[11] == '是') {
                $level = $redis->get('教师');
                $data = [];
                $data['BookId'] = $bookId;
                $data['FitReaderId'] = $level;
                $data['Level'] = 4;
                $res = BookFitReader::on('default')->create($data);
                if (empty($res)) {
                    $item['errlevel'] = 4;
                    $fitReaderErr[] = $item;
                }
            }
        }

        if (count($fitReaderErr) > 0) {
            //记录错误数据
            file_put_contents(self::DATAFILE_PATH . self::FITREADERERR_PROFIX . $taskId . '.json', json_encode($fitReaderErr));
        }

        LogComponent::writeLog()->info('writeBookFitReader list: ' . $taskId . ', error: '.count($fitReaderErr).' total: ' . count($book));
        return 0;
    }

    /**
     * 写入图书类型
     * @param $taskId
     * @return int
     */
    public function writeBookCategory($taskId)
    {
        $categoryErr = [];
        $book = file_get_contents(self::DATAFILE_PATH . self::BOOKDATA_PREFIX . $taskId . '.json');
        $book = json_decode($book, true);
        $redis = new Client();
        foreach ($book as $key => $item) {
            $category = mb_substr($item[2], 0, 1, 'utf-8');
            $class = $redis->get($category);
            $bookId = $redis->get($item[5]);
            $data = [];
            $data['BookId'] = $bookId;
            $data['CategroyId'] = $class;
            $res = BookCategoryMap::on('default')->create($data);
            if (empty($res)) {
                $categoryErr[] = $item;
            }
        }

        if (count($categoryErr) > 0) {
            //记录错误数据
            file_put_contents(self::DATAFILE_PATH . self::CATEGORYERR_PROFIX . $taskId . '.json', json_encode($categoryErr));
        }

        LogComponent::writeLog()->info('writeBookCategory list: ' . $taskId . ', error: '.count($categoryErr).' total: ' . count($book));
        return 0;
    }

    public function writeBookListDetail($data)
    {
        $bookListDetailErr = [];
        $book = file_get_contents(self::DATAFILE_PATH . self::BOOKDATA_PREFIX . $data['taskId'] . '.json');
        $book = json_decode($book, true);
        $redis = new Client();
        foreach ($book as $key => $item) {
            $bookId = $redis->get($item[5]);
            $bookListId = $data['listId'];
            $res = BookListDetail::on('default')->create(['BookListId' => $bookListId, 'BookId' => $bookId]);
            if (empty($res)) {
                $bookListDetailErr[] = $item;
            }
        }

        if (count($bookListDetailErr) > 0) {
            //记录错误数据
            file_put_contents(self::DATAFILE_PATH . self::BOOKLISTDETAILERR_PROFIX . $data['taskId'] . '.json', json_encode($bookListDetailErr));
        }

        LogComponent::writeLog()->info('writeBookListDetail list: ' . $data['taskId'] . ', error: '.count($bookListDetailErr).' total: ' . count($book));
        return 0;
    }

    public function delRedis($taskId)
    {
//        $row = Book::on('default')->find(1);
//        var_dump($row);
        $redis = new Client();
        $arr = $redis->keys("97*");
        foreach ($arr as $item) {
            $redis->del($item);
        }
    }
}